package com.thz.system.service.svg.impl;

import cn.hutool.core.bean.BeanUtil;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.thz.common.dto.svg.ConversionFileToSvgRequestDTO;
import com.thz.common.dto.svg.ConversionFileToSvgResponseDTO;
import com.thz.common.entity.ConversionRecord;
import com.thz.common.entity.ConversionRecordFileToSvg;
import com.thz.common.enums.ConversionStatus;
import com.thz.common.enums.ConversionType;
import com.thz.common.enums.ErrorCode;
import com.thz.common.exception.BusinessException;
import com.thz.common.utils.FileUtils;
import com.thz.system.mapper.svg.ConversionFileToSvgMapper;
import com.thz.system.service.svg.IConversionFileToSvgService;
import com.thz.system.service.user.IUserInfoService;
import com.thz.system.service.record.IConversionRecordService;
import com.thz.system.utils.svg.PythonSvgVectorizer;

import com.thz.system.utils.svg.ImageToSvgUtilsOptimized;
import com.thz.system.config.CosConfig;
import com.thz.system.utils.cos.CosFileUtils;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.time.LocalDateTime;
import java.util.List;
import java.util.stream.Collectors;
import java.util.concurrent.Semaphore;
import java.util.concurrent.TimeUnit;

/**
 * 文件转SVG服务实现类
 * 
 * @author THZ
 * @date 2025
 */
@Slf4j
@Service
public class ConversionFileToSvgServiceImpl implements IConversionFileToSvgService {
    
    @Autowired
    private ConversionFileToSvgMapper conversionRecordMapper;
    
    @Autowired
    private IUserInfoService userInfoService;
    
    @Autowired
    private IConversionRecordService conversionRecordService;
    
    @Autowired
    private CosFileUtils cosFileUtils;
    
    @Autowired
    private CosConfig cosConfig;
    
    @Autowired
    private PythonSvgVectorizer pythonSvgVectorizer;
    
    @Value("${app.domain:http://localhost:9091}")
    private String serverDomain;
    
    /**
     * 限制并发转换数量，避免2C4G机器被打满
     */
    @Value("${svg.max.concurrency:1}")
    private int maxConcurrency;
    private Semaphore svgSemaphore;
    
    @jakarta.annotation.PostConstruct
    public void initConcurrencyLimiter() {
        int permits = Math.max(1, maxConcurrency);
        svgSemaphore = new Semaphore(permits, true);
        log.info("SVG并发限制已启用，最大并发: {}", permits);
    }
    
    @Override
    public ConversionFileToSvgResponseDTO convertFileToSvg(MultipartFile file, ConversionFileToSvgRequestDTO requestDTO, String ipAddress) {
        // 1. 验证文件
        FileUtils.validateImageFile(file);
        
        log.info("开始转换文件为SVG: filename={}, size={}, contentType={}", 
                file.getOriginalFilename(), file.getSize(), file.getContentType());
        
        // 2. 保存上传的图像文件到COS
        String imageFilePath = cosFileUtils.saveUploadFile(file, null, cosConfig.getUploadPrefix());
        log.info("图像文件已保存到COS: {}", imageFilePath);
        
        // 2.1 下载到本地临时目录进行转换
        String tempPath = System.getProperty("java.io.tmpdir") + "/image_" + System.currentTimeMillis() + "." + FileUtils.getFileExtension(file.getOriginalFilename());
        cosFileUtils.downloadToLocal(imageFilePath, tempPath);
        File imageFile = new File(tempPath);
        log.info("COS文件已下载到临时目录: {}", tempPath);
        
        // 3. 获取或创建用户
        com.thz.common.dto.user.UserInfoDTO userInfoDTO = userInfoService.getOrCreateUser(ipAddress);
        
        // 4. 创建转换记录（存储COS URL或本地路径）
        ConversionRecordFileToSvg record = new ConversionRecordFileToSvg();
        record.setOriginalFilename(file.getOriginalFilename());
        record.setOriginalFilePath(imageFilePath);
        record.setOriginalFileSize(file.getSize());
        record.setOriginalFileType(file.getContentType());
        record.setConversionStatus(ConversionStatus.PENDING.getCode());
        record.setIpAddress(ipAddress);
        record.setUserId(userInfoDTO.getId());
        record.setCreateTime(LocalDateTime.now());
        record.setUpdateTime(LocalDateTime.now());
        
        conversionRecordMapper.insert(record);
        
        boolean acquired = false;
        try {
            // 并发限流。若繁忙则快速失败，避免请求堆积导致“卡住”
            acquired = svgSemaphore.tryAcquire(1, 2, TimeUnit.SECONDS);
            if (!acquired) {
                throw new BusinessException(ErrorCode.SERVER_BUSY);
            }
            // 5. 更新状态为转换中
            record.setConversionStatus(ConversionStatus.CONVERTING.getCode());
            conversionRecordMapper.updateById(record);
            
            // 6. 生成SVG文件名和路径
            String svgFilename = FileUtils.generateUniqueFilename(file.getOriginalFilename())
                    .replace(FileUtils.getFileExtension(file.getOriginalFilename()), "svg");
            String tempDir = System.getProperty("java.io.tmpdir");
            File svgFile = new File(tempDir, svgFilename);
            
            // 7. 执行高质量矢量化转换（优先使用Python，否则使用Java版本）
            log.info("开始高质量SVG转换: colorCount={}, precision={}", 
                    requestDTO.getColorCount(), requestDTO.getPrecision());
            
            boolean usePython = pythonSvgVectorizer.isPythonVectorizerAvailable();
            
            if (usePython) {
                log.info("使用Python高质量矢量化");
                pythonSvgVectorizer.convertImageToSvg(
                        imageFile.getAbsolutePath(),
                        svgFile.getAbsolutePath(),
                        requestDTO.getWidth(),
                        requestDTO.getHeight(),
                        requestDTO.getKeepAspectRatio(),
                        requestDTO.getPrecision()
                );
            } else {
                log.info("Python矢量化不可用，使用Java优化版");
                ImageToSvgUtilsOptimized.convertImageToSvg(
                        imageFile.getAbsolutePath(),
                        svgFile.getAbsolutePath(),
                        requestDTO.getWidth(),
                        requestDTO.getHeight(),
                        requestDTO.getKeepAspectRatio(),
                        requestDTO.getColorCount(),
                        requestDTO.getPrecision()
                );
            }
            
            log.info("SVG转换完成: {}", svgFilename);
            
            // 8. SVG压缩优化（如果Python脚本中已压缩，这里会进一步优化）
            long originalSvgSize = svgFile.length();
            log.info("SVG转换后原始大小: {} KB", originalSvgSize / 1024.0);
            
            // 9. 获取SVG文件信息并上传到COS
            long svgSize = svgFile.length();
            int[] dimensions = ImageToSvgUtilsOptimized.getSvgDimensions(svgFile.getAbsolutePath());
            
            String svgPath = cosFileUtils.uploadLocalFile(svgFile, cosConfig.getOutputPrefix());
            svgFile.delete();
            log.info("SVG已上传到COS: path={}, size={} bytes, dimensions={}x{}", 
                    svgPath, svgSize, dimensions[0], dimensions[1]);
            
            // 10. 更新转换记录
            record.setSvgFilename(svgFilename);
            record.setSvgFilePath(svgPath);
            record.setSvgFileSize(svgSize);
            record.setSvgWidth(dimensions[0]);
            record.setSvgHeight(dimensions[1]);
            record.setConversionStatus(ConversionStatus.SUCCESS.getCode());
            record.setUpdateTime(LocalDateTime.now());
            conversionRecordMapper.updateById(record);
            
            // 11. 创建缩略图（使用原始图片）
            String thumbnailPath = createThumbnail(imageFile, tempDir, file.getOriginalFilename(), imageFilePath);
            
            // 12. 清理临时图片文件
            if (imageFile.exists()) {
                imageFile.delete();
            }
            
            // 13. 记录到统一转换记录表
            createUnifiedRecord(userInfoDTO.getId(), ipAddress, record, svgPath, thumbnailPath);
            
            // 14. 更新用户转换次数
            userInfoService.incrementConversions(ipAddress);
            
            log.info("文件转SVG成功: {} -> {}", imageFile.getName(), svgFilename);
            
            // 15. 返回结果
            return buildResponseDTO(record);
            
        } catch (Exception e) {
            log.error("文件转SVG失败", e);
            
            // 清理临时图片文件
            if (imageFile != null && imageFile.exists()) {
                imageFile.delete();
                log.info("失败时清理临时图片文件: {}", imageFile.getAbsolutePath());
            }
            
            // 更新失败状态
            record.setConversionStatus(ConversionStatus.FAILED.getCode());
            record.setErrorMessage(e.getMessage());
            record.setUpdateTime(LocalDateTime.now());
            conversionRecordMapper.updateById(record);
            
            throw new BusinessException(ErrorCode.CONVERSION_FAILED, e.getMessage(), e);
        } finally {
            if (acquired) {
                svgSemaphore.release();
            }
        }
    }
    
    @Override
    public ConversionFileToSvgResponseDTO getConversionRecord(Long id) {
        ConversionRecordFileToSvg record = conversionRecordMapper.selectById(id);
        if (record == null) {
            throw new BusinessException(ErrorCode.CONVERSION_RECORD_NOT_EXISTS);
        }
        return buildResponseDTO(record);
    }
    
    @Override
    public List<ConversionFileToSvgResponseDTO> getRecentConversions(int limit) {
        LambdaQueryWrapper<ConversionRecordFileToSvg> queryWrapper = new LambdaQueryWrapper<>();
        queryWrapper.orderByDesc(ConversionRecordFileToSvg::getCreateTime)
                .last("LIMIT " + limit);
        
        List<ConversionRecordFileToSvg> records = conversionRecordMapper.selectList(queryWrapper);
        return records.stream()
                .map(this::buildResponseDTO)
                .collect(Collectors.toList());
    }
    
    @Override
    public void deleteConversion(Long id) {
        ConversionRecordFileToSvg record = conversionRecordMapper.selectById(id);
        if (record == null) {
            throw new BusinessException(ErrorCode.CONVERSION_RECORD_NOT_EXISTS);
        }
        
        // 删除文件（自动判断COS或本地）
        cosFileUtils.deleteFile(record.getOriginalFilePath());
        cosFileUtils.deleteFile(record.getSvgFilePath());
        
        // 删除记录
        conversionRecordMapper.deleteById(id);
        
        log.info("删除转换记录: {}", id);
    }
    
    /**
     * 创建缩略图
     */
    private String createThumbnail(File imageFile, String tempDir, String originalFilename, String imageFilePath) {
        try {
            String thumbnailFilename = FileUtils.generateUniqueFilename("thumb_" + originalFilename);
            File thumbnailFile = new File(tempDir, thumbnailFilename);
            java.nio.file.Files.copy(imageFile.toPath(), thumbnailFile.toPath());
            
            String thumbnailPath = cosFileUtils.uploadLocalFile(thumbnailFile, cosConfig.getOutputPrefix());
            thumbnailFile.delete();
            
            log.info("缩略图已创建并上传: {}", thumbnailPath);
            return thumbnailPath;
        } catch (Exception e) {
            log.warn("创建缩略图失败，使用原始图片: {}", e.getMessage());
            return imageFilePath;
        }
    }
    
    /**
     * 创建统一转换记录
     */
    private void createUnifiedRecord(Long userId, String ipAddress, ConversionRecordFileToSvg record, 
                                     String svgPath, String thumbnailPath) {
        ConversionRecord unifiedRecord = new ConversionRecord();
        unifiedRecord.setUserId(userId);
        unifiedRecord.setIpAddress(ipAddress);
        unifiedRecord.setConversionType(ConversionType.FILE_TO_SVG.getCode());
        unifiedRecord.setReferenceId(record.getId());
        unifiedRecord.setOriginalFilename(record.getOriginalFilename());
        unifiedRecord.setOutputFilename(svgPath);
        unifiedRecord.setThumbnailFilename(thumbnailPath);
        unifiedRecord.setOriginalFileSize(record.getOriginalFileSize());
        unifiedRecord.setOutputFileSize(record.getSvgFileSize());
        unifiedRecord.setOutputWidth(record.getSvgWidth());
        unifiedRecord.setOutputHeight(record.getSvgHeight());
        unifiedRecord.setConversionStatus(record.getConversionStatus());
        unifiedRecord.setCreateTime(record.getCreateTime());
        unifiedRecord.setUpdateTime(record.getUpdateTime());
        conversionRecordService.createRecord(unifiedRecord);
    }
    
    /**
     * 构建响应DTO
     */
    private ConversionFileToSvgResponseDTO buildResponseDTO(ConversionRecordFileToSvg record) {
        ConversionFileToSvgResponseDTO dto = new ConversionFileToSvgResponseDTO();
        BeanUtil.copyProperties(record, dto);
        
        // 构建SVG访问URL（自动处理COS URL和本地路径）
        if (record.getSvgFilePath() != null) {
            String svgUrl = cosFileUtils.getFileUrl(record.getSvgFilePath(), serverDomain + "/api/files/svg/");
            dto.setSvgUrl(svgUrl);
            dto.setDownloadUrl(svgUrl + "?download=true");
            log.info("构建SVG访问URL: {}, 文件路径: {}, 文件大小: {}, 尺寸: {}x{}", 
                    svgUrl, record.getSvgFilePath(), record.getSvgFileSize(), 
                    record.getSvgWidth(), record.getSvgHeight());
        }
        
        // 格式化文件大小
        dto.setOriginalFileSizeFormatted(FileUtils.formatFileSize(record.getOriginalFileSize()));
        if (record.getSvgFileSize() != null) {
            dto.setSvgFileSizeFormatted(FileUtils.formatFileSize(record.getSvgFileSize()));
            
            // 计算压缩率
            if (record.getOriginalFileSize() > 0) {
                double ratio = (1.0 - (double) record.getSvgFileSize() / record.getOriginalFileSize()) * 100;
                dto.setCompressionRatio(Math.max(0, ratio));
            }
        }
        
        return dto;
    }
}

